
// `timescale 1 ns / 1 ps
module soc_top #(
    parameter int unsigned AXI_ID_WIDTH      = 8,
    parameter int unsigned AXI_ADDR_WIDTH    = 40,
    parameter int unsigned AXI_DATA_WIDTH    = 128,
    parameter int unsigned AXI_USER_WIDTH    = 2
)();



wire                            axi_aw_valid;
wire                            axi_aw_ready;
wire   [AXI_ADDR_WIDTH-1:0]     axi_aw_addr;
wire   [AXI_ID_WIDTH-1  :0]     axi_aw_id;
wire   [7:0]                    axi_aw_len;
wire   [2:0]                    axi_aw_size;
wire   [1:0]                    axi_aw_burst;
wire   [3:0]                    axi_aw_cache;
wire   [2:0]                    axi_aw_prot;
wire                            axi_w_valid;
wire                            axi_w_ready;
wire   [AXI_ID_WIDTH-1  :0]     axi_w_id;
wire   [AXI_DATA_WIDTH-1:0]     axi_w_data;
wire   [15:0]                   axi_w_strb;
wire                            axi_w_last;
wire                            axi_b_valid;
wire                            axi_b_ready;
wire   [AXI_ID_WIDTH-1  :0]     axi_b_id;
wire   [1:0]                    axi_b_resp;
wire                            axi_ar_valid;
wire                            axi_ar_ready;
wire   [AXI_ADDR_WIDTH-1:0]     axi_ar_addr;
wire   [AXI_ID_WIDTH-1  :0]     axi_ar_id;
wire   [7:0]                    axi_ar_len;
wire   [2:0]                    axi_ar_size;
wire   [1:0]                    axi_ar_burst;
wire   [3:0]                    axi_ar_cache;
wire   [2:0]                    axi_ar_prot;
wire                            axi_r_valid;
wire                            axi_r_ready;
wire   [AXI_DATA_WIDTH-1:0]     axi_r_data;
wire   [AXI_ID_WIDTH-1  :0]     axi_r_id;
wire   [1:0]                    axi_r_resp;
wire                            axi_r_last;


wire                            mem_aw_valid;
wire                            mem_aw_ready;
wire   [AXI_ADDR_WIDTH-1:0]     mem_aw_addr;
wire   [AXI_ID_WIDTH-1  :0]     mem_aw_id;
wire   [7:0]                    mem_aw_len;
wire   [2:0]                    mem_aw_size;
wire   [1:0]                    mem_aw_burst;
wire   [3:0]                    mem_aw_cache;
wire   [2:0]                    mem_aw_prot;
wire                            mem_w_valid;
wire                            mem_w_ready;
wire   [AXI_ID_WIDTH-1  :0]     mem_w_id;
wire   [AXI_DATA_WIDTH-1:0]     mem_w_data;
wire   [15:0]                   mem_w_strb;
wire                            mem_w_last;
wire                            mem_b_valid;
wire                            mem_b_ready;
wire   [AXI_ID_WIDTH-1  :0]     mem_b_id;
wire   [1:0]                    mem_b_resp;
wire                            mem_ar_valid;
wire                            mem_ar_ready;
wire   [AXI_ADDR_WIDTH-1:0]     mem_ar_addr;
wire   [AXI_ID_WIDTH-1  :0]     mem_ar_id;
wire   [7:0]                    mem_ar_len;
wire   [2:0]                    mem_ar_size;
wire   [1:0]                    mem_ar_burst;
wire   [3:0]                    mem_ar_cache;
wire   [2:0]                    mem_ar_prot;
wire                            mem_r_valid;
wire                            mem_r_ready;
wire   [AXI_DATA_WIDTH-1:0]     mem_r_data;
wire   [AXI_ID_WIDTH-1  :0]     mem_r_id;
wire   [1:0]                    mem_r_resp;
wire                            mem_r_last;


wire             arready_s0;           
wire             arready_s1;           
wire             arready_s2;           
wire             arready_s3;           
wire             arvalid_s0;           
wire             arvalid_s1;           
wire             arvalid_s2;           
wire             arvalid_s3;           
wire             awready_s0;           
wire             awready_s1;           
wire             awready_s2;           
wire             awready_s3;           
wire             awvalid_s0;           
wire             awvalid_s1;           
wire             awvalid_s2;           
wire             awvalid_s3;           
wire    [7  :0]  b_pad_gpio_porta;     
wire    [7  :0]  bid_s0;               
wire    [7  :0]  bid_s1;               
wire    [7  :0]  bid_s2;               
wire    [7  :0]  bid_s3;               
wire    [39 :0]  biu_pad_araddr;       
wire    [1  :0]  biu_pad_arburst;      
wire    [3  :0]  biu_pad_arcache;      
wire    [7  :0]  biu_pad_arid;         
wire    [7  :0]  biu_pad_arlen;        
wire             biu_pad_arlock;       
wire    [2  :0]  biu_pad_arprot;       
wire    [2  :0]  biu_pad_arsize;       
wire             biu_pad_arvalid;      
wire    [39 :0]  biu_pad_awaddr;       
wire    [1  :0]  biu_pad_awburst;      
wire    [3  :0]  biu_pad_awcache;      
wire    [7  :0]  biu_pad_awid;         
wire    [7  :0]  biu_pad_awlen;        
wire             biu_pad_awlock;       
wire    [2  :0]  biu_pad_awprot;       
wire    [2  :0]  biu_pad_awsize;       
wire             biu_pad_awvalid;      
wire             biu_pad_bready;       
wire    [39 :0]  biu_pad_haddr;        
wire    [2  :0]  biu_pad_hburst;       
wire             biu_pad_hbusreq;      
wire             biu_pad_hlock;        
wire    [3  :0]  biu_pad_hprot;        
wire    [2  :0]  biu_pad_hsize;        
wire    [1  :0]  biu_pad_htrans;       
wire    [1  :0]  biu_pad_htrans_dly;   
wire    [127:0]  biu_pad_hwdata;       
wire             biu_pad_hwrite;       
wire             biu_pad_hwrite_dly;   
wire    [1  :0]  biu_pad_lpmd_b;       
wire             biu_pad_rready;       
wire    [127:0]  biu_pad_wdata;        
wire    [7  :0]  biu_pad_wid;          
wire             biu_pad_wlast;        
wire    [15 :0]  biu_pad_wstrb;        
wire             biu_pad_wvalid;       
wire             bready_s0;            
wire             bready_s1;            
wire             bready_s2;            
wire             bready_s3;            
wire    [1  :0]  bresp_s0;             
wire    [1  :0]  bresp_s1;             
wire    [1  :0]  bresp_s2;             
wire    [1  :0]  bresp_s3;             
wire             bvalid_s0;            
wire             bvalid_s1;            
wire             bvalid_s2;            
wire             bvalid_s3;            
wire             axim_clk_en;               
wire             fifo_biu_arready;     
wire    [39 :0]  fifo_pad_araddr;      
wire    [1  :0]  fifo_pad_arburst;     
wire    [3  :0]  fifo_pad_arcache;     
wire    [7  :0]  fifo_pad_arid;        
wire    [7  :0]  fifo_pad_arlen;       
wire             fifo_pad_arlock;      
wire    [2  :0]  fifo_pad_arprot;      
wire    [2  :0]  fifo_pad_arsize;      
wire             fifo_pad_artrust;     
wire             fifo_pad_arvalid;     
wire             had_pad_jtg_tdo;      
wire             had_pad_jtg_tdo_en;      
wire    [39 :0]  haddr_dly;            
wire    [39 :0]  haddr_s1;             
wire    [39 :0]  haddr_s2;             
wire    [39 :0]  haddr_s3;             
wire    [2  :0]  hburst_s1;            
wire    [2  :0]  hburst_s2;            
wire    [2  :0]  hburst_s3;            
wire             hmastlock;            
wire    [3  :0]  hprot_s1;             
wire    [3  :0]  hprot_s2;             
wire    [3  :0]  hprot_s3;             
wire    [127:0]  hrdata_s1;            
wire    [127:0]  hrdata_s2;            
wire    [127:0]  hrdata_s3;            
wire             hready_s1;            
wire             hready_s2;            
wire             hready_s3;            
wire    [1  :0]  hresp_s1;             
wire    [1  :0]  hresp_s2;             
wire    [1  :0]  hresp_s3;             
wire             hsel_s1;              
wire             hsel_s2;              
wire             hsel_s3;              
wire    [2  :0]  hsize_s1;             
wire    [2  :0]  hsize_s2;             
wire    [2  :0]  hsize_s3;             
wire    [1  :0]  htrans_s1;            
wire    [1  :0]  htrans_s2;            
wire    [1  :0]  htrans_s3;            
wire    [127:0]  hwdata_s1;            
wire    [127:0]  hwdata_s2;            
wire    [127:0]  hwdata_s3;            
wire             hwrite_s1;            
wire             hwrite_s2;            
wire             hwrite_s3;            
wire             i_pad_clk;            
wire             cpu_clk;            
wire             i_pad_jtg_tclk;       
wire             i_pad_jtg_tdi;        
wire             i_pad_jtg_tms;        
wire             i_pad_jtg_trst_b;     
wire             i_pad_rst_b;          
wire             i_pad_uart0_sin;      
wire             o_pad_jtg_tdo;        
wire             o_pad_uart0_sout;     
wire             pad_biu_arready;      
wire             pad_biu_awready;      
wire    [7  :0]  pad_biu_bid;          
wire    [1  :0]  pad_biu_bresp;        
wire             pad_biu_bvalid;       
wire             pad_biu_hgrant;       
wire    [127:0]  pad_biu_hrdata;       
wire             pad_biu_hready;       
wire    [1  :0]  pad_biu_hresp;        
wire    [127:0]  pad_biu_rdata;        
wire    [7  :0]  pad_biu_rid;          
wire             pad_biu_rlast;        
wire    [1  :0]  pad_biu_rresp;        
wire             pad_biu_rvalid;       
wire             pad_biu_wready;       
wire             pad_cpu_rst_b;        
wire             pad_had_jtg_tclk;     
wire             pad_had_jtg_tdi;      
wire             pad_had_jtg_trst_b;   
wire             per_clk;              
wire             pll_cpu_clk;      
wire    [127:0]  rdata_s0;             
wire    [127:0]  rdata_s1;             
wire    [127:0]  rdata_s2;             
wire    [127:0]  rdata_s3;             
wire    [7  :0]  rid_s0;               
wire    [7  :0]  rid_s1;               
wire    [7  :0]  rid_s2;               
wire    [7  :0]  rid_s3;               
wire             rlast_s0;             
wire             rlast_s1;             
wire             rlast_s2;             
wire             rlast_s3;             
wire             rready_s0;            
wire             rready_s1;            
wire             rready_s2;            
wire             rready_s3;            
wire    [1  :0]  rresp_s0;             
wire    [1  :0]  rresp_s1;             
wire    [1  :0]  rresp_s2;             
wire    [1  :0]  rresp_s3;             
wire             rvalid_s0;            
wire             rvalid_s1;            
wire             rvalid_s2;            
wire             rvalid_s3;            
wire             uart0_sin;            
wire             uart0_sout;           
wire             wready_s0;            
wire             wready_s1;            
wire             wready_s2;            
wire             wready_s3;            
wire             wvalid_s0;            
wire             wvalid_s1;            
wire             wvalid_s2;            
wire             wvalid_s3;            
wire    [39 :0]  xx_intc_vld;          
wire    [7  :0]  ext_interrupt;


parameter CLK_PREF   = 250000000; // 250MHz
parameter CLK_PEROID = (1000000000/CLK_PREF)/2;


reg gl_clk;
initial begin 
  gl_clk = 0;
  forever begin
    #(CLK_PEROID) gl_clk = ~gl_clk;
  end
end

reg reset;
initial begin
  reset = 1;
  #10;
  reset = 1;
  #80;
  reset = 0;

  // #2000000
  // $finish;  
end

reg jrst_b;
initial
begin
  jrst_b = 1;
  #400;
  jrst_b = 0;
  #400;
  jrst_b = 1;
end


`ifdef VERDI_DUMP
initial begin
      /// method 1: this will dump only ct_top module
      $fsdbDumpon;
      $fsdbDumpfile("soc_top.fsdb");
      $fsdbDumpvars(0, soc_top);

      /// method 2: this will dump all module
      // $fsdbDumpvars();
end
`endif


wire    [39:0]   core_in_interrupt;

assign  pad_had_jtg_tclk  = gl_clk;
assign	pad_cpu_rst_b = ~reset;
assign  pad_had_jtg_tdi   = '0;
assign  core_in_interrupt[39:0] = {40'b0};

assign  ext_interrupt[7:0] = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

cpu_subsystem  cpu_subsystem (
  // AR
  .biu_pad_araddr        (axi_ar_addr       ),
  .biu_pad_arburst       (axi_ar_burst      ),
  .biu_pad_arcache       (axi_ar_cache      ),
  .biu_pad_arid          (axi_ar_id         ),
  .biu_pad_arlen         (axi_ar_len        ),
  .biu_pad_arlock        (axi_ar_lock       ),
  .biu_pad_arprot        (axi_ar_prot       ),
  .biu_pad_arsize        (axi_ar_size       ),
  .biu_pad_arvalid       (axi_ar_valid      ),
  .pad_biu_arready       (axi_ar_ready      ),
  
  // AW
  .biu_pad_awaddr        (axi_aw_addr       ),
  .biu_pad_awburst       (axi_aw_burst      ),
  .biu_pad_awcache       (axi_aw_cache      ),
  .biu_pad_awid          (axi_aw_id         ),
  .biu_pad_awlen         (axi_aw_len        ),
  .biu_pad_awlock        (axi_aw_lock       ),
  .biu_pad_awprot        (axi_aw_prot       ),
  .biu_pad_awsize        (axi_aw_size       ),
  .biu_pad_awvalid       (axi_aw_valid      ),
  .pad_biu_awready       (axi_aw_ready      ),
  
  // W
  .biu_pad_wdata         (axi_w_data        ),
  .biu_pad_wid           (axi_w_id          ),
  .biu_pad_wlast         (axi_w_last        ),
  .biu_pad_wstrb         (axi_w_strb        ),
  .biu_pad_wvalid        (axi_w_valid       ),
  .pad_biu_wready        (axi_w_ready       ),
  
  // B
  .biu_pad_bready        (axi_b_ready       ),
  .pad_biu_bid           (axi_b_id          ),
  .pad_biu_bresp         (axi_b_resp        ),
  .pad_biu_bvalid        (axi_b_valid       ),
  
  // R
  .biu_pad_rready        (axi_r_ready       ),
  .pad_biu_rdata         (axi_r_data        ),
  .pad_biu_rid           (axi_r_id          ),
  .pad_biu_rlast         (axi_r_last        ),
  .pad_biu_rresp         ({2'b0,axi_r_resp} ),
  .pad_biu_rvalid        (axi_r_valid       ),

  /// MISC
  .axim_clk_en           (1'b1              ),
  .biu_pad_lpmd_b        (biu_pad_lpmd_b    ),
  .had_pad_jtg_tdo       (                  ),
  .had_pad_jtg_tdo_en    (                  ),
  .i_pad_jtg_tms         (                  ),  /// No Input
  .pad_cpu_rst_b         (pad_cpu_rst_b     ),
  .pad_yy_dft_clk_rst_b  (pad_cpu_rst_b     ),
  .pad_had_jtg_tclk      (pad_had_jtg_tclk  ),
  .pad_had_jtg_tdi       ('0      			    ),
  .pad_had_jtg_trst_b    (jrst_b            ),
  .pll_cpu_clk           (gl_clk        	  ),
  .ext_interrupt         (ext_interrupt     ),
  .xx_intc_vld           (core_in_interrupt )
);


//==========================================================
//                 AXI Interconnect
//==========================================================

// S0 => memory
// S1 => dummy
// S2 => AHB
// S3 => dummy

axi_interconnect128  x_axi_interconnect (
  .aclk             (gl_clk          ),
  .aresetn          (pad_cpu_rst_b   ),

  .araddr           (axi_ar_addr     ),
  .arready          (axi_ar_ready    ),
  .arready_s0       (mem_ar_ready    ),
  .arready_s1       (1'b1            ),
  .arready_s2       (arready_s2      ),
  .arready_s3       (1'b1            ),
  .arvalid          (axi_ar_valid    ),
  .arvalid_s0       (mem_ar_valid    ),
  .arvalid_s1       (arvalid_s1      ),
  .arvalid_s2       (arvalid_s2      ),
  .arvalid_s3       (arvalid_s3      ),
  .awaddr           (axi_aw_addr     ),
  .awid             (axi_aw_id       ),
  .awready          (axi_aw_ready    ),
  .awready_s0       (mem_aw_ready    ),
  .awready_s1       (1'b1            ),
  .awready_s2       (awready_s2      ),
  .awready_s3       (1'b1            ),
  .awvalid          (axi_aw_valid    ),
  .awvalid_s0       (mem_aw_valid    ),
  .awvalid_s1       (awvalid_s1      ),
  .awvalid_s2       (awvalid_s2      ),
  .awvalid_s3       (awvalid_s3      ),
  .bid              (axi_b_id        ),
  .bid_s0           (mem_b_id        ),
  .bid_s1           ('0              ),
  .bid_s2           (bid_s2          ),
  .bid_s3           ('0              ),
  .bready           (axi_b_ready     ),
  .bready_s0        (mem_b_ready     ),
  .bready_s1        (bready_s1       ),
  .bready_s2        (bready_s2       ),
  .bready_s3        (bready_s3       ),
  .bresp            (axi_b_resp      ),
  .bresp_s0         (mem_b_resp      ),
  .bresp_s1         ('0              ),
  .bresp_s2         (bresp_s2        ),
  .bresp_s3         ('0              ),
  .bvalid           (axi_b_valid     ),
  .bvalid_s0        (mem_b_valid     ),
  .bvalid_s1        ('0              ),
  .bvalid_s2        (bvalid_s2       ),
  .bvalid_s3        ('0              ),
  .rdata            (axi_r_data      ),
  .rdata_s0         (mem_r_data      ),
  .rdata_s1         ('0              ),
  .rdata_s2         (rdata_s2        ),
  .rdata_s3         ('0              ),
  .rid              (axi_r_id        ),
  .rid_s0           (mem_r_id        ),
  .rid_s1           ('0              ),
  .rid_s2           (rid_s2          ),
  .rid_s3           ('0              ),
  .rlast            (axi_r_last      ),
  .rlast_s0         (mem_r_last      ),
  .rlast_s1         ('0              ),
  .rlast_s2         (rlast_s2        ),
  .rlast_s3         ('0              ),
  .rready           (axi_r_ready     ),
  .rready_s0        (mem_r_ready     ),
  .rready_s1        (                ),
  .rready_s2        (rready_s2       ),
  .rready_s3        (                ),
  .rresp            (axi_r_resp      ),
  .rresp_s0         (mem_r_resp      ),
  .rresp_s1         ('0              ),
  .rresp_s2         (rresp_s2        ),
  .rresp_s3         ('0              ),
  .rvalid           (axi_r_valid     ),
  .rvalid_s0        (mem_r_valid     ),
  .rvalid_s1        ('0              ),
  .rvalid_s2        (rvalid_s2       ),
  .rvalid_s3        ('0              ),
  .wid              (axi_w_id        ),
  .wlast            (axi_w_last      ),
  .wready           (axi_w_ready     ),
  .wready_s0        (mem_w_ready     ),
  .wready_s1        ('0              ),
  .wready_s2        (wready_s2       ),
  .wready_s3        ('0              ),
  .wvalid           (axi_w_valid     ),
  .wvalid_s0        (mem_w_valid     ),
  .wvalid_s1        (wvalid_s1       ),
  .wvalid_s2        (wvalid_s2       ),
  .wvalid_s3        (wvalid_s3       )
);


// axi_fifo  x_axi_fifo (
//   .biu_pad_araddr   (axi_ar_addr  ),
//   .biu_pad_arburst  (axi_ar_burst ),
//   .biu_pad_arcache  (axi_ar_cache ),
//   .biu_pad_arid     (axi_ar_id    ),
//   .biu_pad_arlen    (axi_ar_len   ),
//   .biu_pad_arlock   ('0           ),
//   .biu_pad_arprot   (axi_ar_prot  ),
//   .biu_pad_arsize   (axi_ar_size  ),
//   .biu_pad_arvalid  (axi_ar_valid ),
//   .pad_biu_arready  (fifo_biu_arready),
//   .counter_num0     (32'd0           ),
//   .counter_num1     (32'd0           ),
//   .counter_num2     (32'd0           ),
//   .counter_num3     (32'd0           ),
//   .counter_num4     (32'd0           ),
//   .counter_num5     (32'd0           ),
//   .counter_num6     (32'd0           ),
//   .counter_num7     (32'd0           ),
//   .cpu_clk          (per_clk         ),
//   .cpu_rst_b        (pad_cpu_rst_b   ),
//   .fifo_biu_arready (axi_ar_ready    ),
//   .fifo_pad_araddr  (fifo_pad_araddr ),
//   .fifo_pad_arburst (fifo_pad_arburst),
//   .fifo_pad_arcache (fifo_pad_arcache),
//   .fifo_pad_arid    (fifo_pad_arid   ),
//   .fifo_pad_arlen   (fifo_pad_arlen  ),
//   .fifo_pad_arlock  (fifo_pad_arlock ),
//   .fifo_pad_arprot  (fifo_pad_arprot ),
//   .fifo_pad_arsize  (fifo_pad_arsize ),
//   .fifo_pad_artrust (fifo_pad_artrust),
//   .fifo_pad_arvalid (fifo_pad_arvalid)
  
// );

//----------------------------------------------------------
//                     Memory Interface
//----------------------------------------------------------
logic                        req;
logic                        we;
logic [AXI_ADDR_WIDTH-1:0]   addr;
logic [AXI_DATA_WIDTH/8-1:0] be;
logic [AXI_DATA_WIDTH-1:0]   rdata;
logic [AXI_DATA_WIDTH-1:0]   wdata;

assign mem_aw_addr[AXI_ADDR_WIDTH-1:0] = axi_aw_addr[AXI_ADDR_WIDTH-1:0];
assign mem_aw_id[AXI_ID_WIDTH-1:0]     = axi_aw_id[AXI_ID_WIDTH-1:0];
assign mem_aw_len[7:0]                 = axi_aw_len[7:0];
assign mem_aw_size[2:0]                = axi_aw_size[2:0];
assign mem_aw_burst[1:0]               = axi_aw_burst[1:0];
assign mem_aw_cache[3:0]               = axi_aw_cache[3:0];
assign mem_aw_prot[2:0]                = axi_aw_prot[2:0];

assign mem_w_data[AXI_DATA_WIDTH-1:0]  = axi_w_data[AXI_DATA_WIDTH-1:0];
assign mem_w_strb[15:0]                = axi_w_strb[15:0];
assign mem_w_last                      = axi_w_last;

assign mem_ar_addr[AXI_ADDR_WIDTH-1:0] = axi_ar_addr[AXI_ADDR_WIDTH-1:0];
assign mem_ar_id[AXI_ID_WIDTH-1:0]     = axi_ar_id[AXI_ID_WIDTH-1:0];
assign mem_ar_len[7:0]                 = axi_ar_len[7:0];
assign mem_ar_size[2:0]                = axi_ar_size[2:0];
assign mem_ar_burst[1:0]               = axi_ar_burst[1:0];
assign mem_ar_cache[3:0]               = axi_ar_cache[3:0];
assign mem_ar_prot[2:0]                = axi_ar_prot[2:0];

axi_mem_if #(
    .AXI_ID_WIDTH    (AXI_ID_WIDTH),
    .AXI_ADDR_WIDTH  (AXI_ADDR_WIDTH),
    .AXI_DATA_WIDTH  (AXI_DATA_WIDTH),
    .AXI_USER_WIDTH  (AXI_USER_WIDTH)
) mem_if (
    .clk_i            (gl_clk),
    .rst_ni           (~reset),
    .aw_valid         (mem_aw_valid), 
    .aw_ready         (mem_aw_ready), 
    .aw_addr          (mem_aw_addr), 
    .aw_id            (mem_aw_id), 
    .aw_len           (mem_aw_len), 
    .aw_size          (mem_aw_size), 
    .aw_burst         (mem_aw_burst), 
    .aw_cache         (mem_aw_cache), 
    .aw_prot          (mem_aw_prot),
    .w_valid          (mem_w_valid), 
    .w_ready          (mem_w_ready), 
    .w_data           (mem_w_data), 
    .w_strb           (mem_w_strb), 
    .w_last           (mem_w_last),
    .b_valid          (mem_b_valid), 
    .b_ready          (mem_b_ready),
    .b_id             (mem_b_id),
    .b_resp           (mem_b_resp),
    .ar_valid         (mem_ar_valid), 
    .ar_ready         (mem_ar_ready), 
    .ar_addr          (mem_ar_addr), 
    .ar_id            (mem_ar_id), 
    .ar_len           (mem_ar_len), 
    .ar_size          (mem_ar_size), 
    .ar_burst         (mem_ar_burst), 
    .ar_cache         (mem_ar_cache), 
    .ar_prot          (mem_ar_prot),
    .r_valid          (mem_r_valid), 
    .r_ready          (mem_r_ready), 
    .r_data           (mem_r_data), 
    .r_id             (mem_r_id), 
    .r_resp           (mem_r_resp), 
    .r_last           (mem_r_last),

    .req_o            (req),
    .we_o             (we),
    .addr_o           (addr),
    .be_o             (be),
    .data_o           (wdata),
    .data_i           (rdata)
);


slave_ram #(
    .AXI_ID_WIDTH    (AXI_ID_WIDTH),
    .AXI_ADDR_WIDTH  (AXI_ADDR_WIDTH),
    .AXI_DATA_WIDTH  (AXI_DATA_WIDTH),
    .AXI_USER_WIDTH  (AXI_USER_WIDTH)
) sys_ram(
    .clk              (gl_clk),
    .reset            (reset),
    .req_i            (req),
    .we_i             (we),
    .addr_i           (addr),
    .be_i             (be),
    .data_i           (wdata),
    .data_o           (rdata)
);



//----------------------------------------------------------
//                     AHB Interface
//----------------------------------------------------------
axi2ahb  x_axi2ahb (
  .biu_pad_araddr   (axi_ar_addr     ),
  .biu_pad_arburst  (axi_ar_burst    ),
  .biu_pad_arcache  (axi_ar_cache    ),
  .biu_pad_arid     (axi_ar_id       ),
  .biu_pad_arlen    (axi_ar_len      ),
  .biu_pad_arlock   (axi_ar_lock     ),
  .biu_pad_arprot   (axi_ar_prot     ),
  .biu_pad_arsize   (axi_ar_size     ),
  .biu_pad_artrust  ('0              ),
  .biu_pad_arvalid  (arvalid_s2      ),
  .biu_pad_awaddr   (axi_aw_addr     ),
  .biu_pad_awburst  (axi_aw_burst    ),
  .biu_pad_awcache  (axi_aw_cache    ),
  .biu_pad_awid     (axi_aw_id       ),
  .biu_pad_awlen    (axi_aw_len      ),
  .biu_pad_awlock   (axi_aw_lock     ),
  .biu_pad_awprot   (axi_aw_prot     ),
  .biu_pad_awsize   (axi_aw_size     ),
  .biu_pad_awvalid  (awvalid_s2      ),
  .biu_pad_bready   (bready_s2       ),
  .biu_pad_haddr    (biu_pad_haddr   ),
  .biu_pad_hburst   (biu_pad_hburst  ),
  .biu_pad_hbusreq  (biu_pad_hbusreq ),
  .biu_pad_hlock    (biu_pad_hlock   ),
  .biu_pad_hprot    (biu_pad_hprot   ),
  .biu_pad_hsize    (biu_pad_hsize   ),
  .biu_pad_htrans   (biu_pad_htrans  ),
  .biu_pad_hwdata   (biu_pad_hwdata  ),
  .biu_pad_hwrite   (biu_pad_hwrite  ),
  .biu_pad_rready   (rready_s2       ),
  .biu_pad_wdata    (axi_w_data      ),
  .biu_pad_wid      (axi_w_id        ),
  .biu_pad_wlast    (axi_w_last      ),
  .biu_pad_wstrb    (axi_w_strb      ),
  .biu_pad_wvalid   (wvalid_s2       ),
  .pad_biu_arready  (arready_s2      ),
  .pad_biu_awready  (awready_s2      ),
  .pad_biu_bid      (bid_s2          ),
  .pad_biu_bresp    (bresp_s2        ),
  .pad_biu_bvalid   (bvalid_s2       ),
  .pad_biu_hgrant   (pad_biu_hgrant  ),
  .pad_biu_hrdata   (pad_biu_hrdata  ),
  .pad_biu_hready   (pad_biu_hready  ),
  .pad_biu_hresp    (pad_biu_hresp   ),
  .pad_biu_rdata    (rdata_s2        ),
  .pad_biu_rid      (rid_s2          ),
  .pad_biu_rlast    (rlast_s2        ),
  .pad_biu_rresp    (rresp_s2        ),
  .pad_biu_rvalid   (rvalid_s2       ),
  .pad_biu_wready   (wready_s2       ),
  .pad_cpu_rst_b    (pad_cpu_rst_b   ),
  .pll_core_cpuclk  (gl_clk          )
);


ahb  x_ahb (
  .biu_pad_haddr      (biu_pad_haddr     ),
  .biu_pad_hburst     (biu_pad_hburst    ),
  .biu_pad_hbusreq    (biu_pad_hbusreq   ),
  .biu_pad_hlock      (biu_pad_hlock     ),
  .biu_pad_hprot      (biu_pad_hprot     ),
  .biu_pad_hsize      (biu_pad_hsize     ),
  .biu_pad_htrans     (biu_pad_htrans    ),
  .biu_pad_hwdata     (biu_pad_hwdata    ),
  .biu_pad_hwrite     (biu_pad_hwrite    ),
  .haddr_s1           (haddr_s1          ),
  .haddr_s2           (haddr_s2          ),
  .haddr_s3           (haddr_s3          ),
  .hburst_s1          (hburst_s1         ),
  .hburst_s2          (hburst_s2         ),
  .hburst_s3          (hburst_s3         ),
  .hmastlock          (hmastlock         ),
  .hprot_s1           (hprot_s1          ),
  .hprot_s2           (hprot_s2          ),
  .hprot_s3           (hprot_s3          ),
  .hrdata_s1          (hrdata_s1         ),
  .hrdata_s2          (hrdata_s2         ),
  .hrdata_s3          (hrdata_s3         ),
  .hready_s1          (hready_s1         ),
  .hready_s2          (hready_s2         ),
  .hready_s3          (hready_s3         ),
  .hresp_s1           (hresp_s1          ),
  .hresp_s2           (hresp_s2          ),
  .hresp_s3           (hresp_s3          ),
  .hsel_s1            (hsel_s1           ),
  .hsel_s2            (hsel_s2           ),
  .hsel_s3            (hsel_s3           ),
  .hsize_s1           (hsize_s1          ),
  .hsize_s2           (hsize_s2          ),
  .hsize_s3           (hsize_s3          ),
  .htrans_s1          (htrans_s1         ),
  .htrans_s2          (htrans_s2         ),
  .htrans_s3          (htrans_s3         ),
  .hwdata_s1          (hwdata_s1         ),
  .hwdata_s2          (hwdata_s2         ),
  .hwdata_s3          (hwdata_s3         ),
  .hwrite_s1          (hwrite_s1         ),
  .hwrite_s2          (hwrite_s2         ),
  .hwrite_s3          (hwrite_s3         ),
  .pad_biu_hgrant     (pad_biu_hgrant    ),
  .pad_biu_hrdata     (pad_biu_hrdata    ),
  .pad_biu_hready     (pad_biu_hready    ),
  .pad_biu_hresp      (pad_biu_hresp     ),
  .pad_cpu_rst_b      (pad_cpu_rst_b     ),
  .pll_core_cpuclk    (gl_clk            )
);



apb  x_apb (
  .b_pad_gpio_porta (b_pad_gpio_porta),
  .biu_pad_haddr    (biu_pad_haddr   ),
  .biu_pad_hprot    (biu_pad_hprot   ),
  .biu_pad_lpmd_b   (biu_pad_lpmd_b  ),
  .clk_en           (axim_clk_en     ),
  .haddr            (haddr_s1        ),
  .hburst           (hburst_s1       ),
  .hmastlock        (hmastlock       ),
  .hprot            (hprot_s1        ),
  .hrdata           (hrdata_s1       ),
  .hready           (hready_s1       ),
  .hresp            (hresp_s1        ),
  .hsel             (hsel_s1         ),
  .hsize            (hsize_s1        ),
  .htrans           (htrans_s1       ),
  .hwdata           (hwdata_s1       ),
  .hwrite           (hwrite_s1       ),
  .i_pad_clk        (gl_clk          ),
  .pad_biu_clkratio (                ),
  .pad_cpu_rst_b    (pad_cpu_rst_b   ),
  .per_clk          (per_clk         ),
  .cpu_clk          (cpu_clk         ),
  .uart0_sin        (uart0_sin       ),
  .uart0_sout       (uart0_sout      ),
  .xx_intc_vld      (xx_intc_vld     )
);


assign hrdata_s2[127:0] = '0;
assign hready_s2        = '0;
assign hresp_s2[1:0]    = '0;     

assign hrdata_s3[127:0] = '0;
assign hready_s3        = '0;
assign hresp_s3[1:0]    = '0; 


`define CPU_CORE cpu_subsystem.core0_subsystem

`ifdef MMU_ON
`define HALT_PC  40'h1800018000
`else 
`define HALT_PC  40'h1c018000
`endif

always @(posedge gl_clk) begin
    if ((`CPU_CORE.core0_pad_retire0_pc == `HALT_PC)
        && `CPU_CORE.core0_pad_retire0
    || (`CPU_CORE.core0_pad_retire1_pc == `HALT_PC)
        && `CPU_CORE.core0_pad_retire1
    || (`CPU_CORE.core0_pad_retire2_pc == `HALT_PC)
        && `CPU_CORE.core0_pad_retire2
        ) begin
        $finish;
    end
end






///NOTE: The following way is too too slow. Deprecated!
/// --------------------- Initial --------------------------- ///
// string binary = "vmlinux";

// for faster simulation we can directly preload the ELF
// Note that we are loosing the capabilities to use risc-fesvr though
// initial begin
//     automatic logic [15:0][7:0] mem_row;
//     longint address, len;
//     byte buffer[];
//     int percent = 0;
//     if (binary != "") begin
//         $display("Preloading ELF: %s", binary);
//         void'(read_elf(binary));
//         // wait with preloading, otherwise randomization will overwrite the existing value
//         wait(gl_clk);
//         // while there are more sections to process
//         while (get_section(address, len)) begin
//             automatic int num_words = (len+15)/16;
//             automatic int per_tmp = num_words / 100 ;
//             automatic int ii = 0;
//             automatic int iii = 0;
//             $display("Loading Address: %x, Length: %x", address, len);
//             $display("Length num_words: %x", num_words);
//             buffer = new [num_words*16];
//             void'(read_section(address, buffer));
//             // preload memories
//             // 128-bit
//             for ( int i = 0; i < num_words; i++) begin
//                 mem_row = '0;
//                 iii++;
//                 for (int j = 0; j < 16; j++) begin
//                     mem_row[j] = buffer[i*16 + j];
//                 end
//                 if (per_tmp == iii) begin
//                     iii = 0;
//                     ii ++;
//                     $display("Length num_words percent: %d", ii);
//                 end
//                 sys_ram.ram_mem[address[47:0]>>4 + i][127:0] = mem_row;

//             end
//         end
//         $display("Loading ELF Successfully!");
//     end
// end

endmodule